home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ADA Programming Guide
/
ADA Programming Guide.iso
/
ada_gwu
/
expr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-30
|
57KB
|
1,905 lines
/*
* Copyright (C) 1985-1992 New York University
*
* This file is part of the Ada/Ed-C system. See the Ada/Ed README file for
* warranty (none) and distribution info and also the GNU General Public
* License for more details.
*/
#define GEN
#include "hdr.h"
#include "vars.h"
#include "segment.h"
#include "gvars.h"
#include "attr.h"
#include "ops.h"
#include "type.h"
#include "namp.h"
#include "segmentp.h"
#include "genp.h"
#include "miscp.h"
#include "maincasp.h"
#include "setp.h"
#include "typep.h"
#include "gutilp.h"
#include "arithp.h"
#include "gmiscp.h"
#include "smiscp.h"
#include "chapp.h"
#include "axqrp.h"
#include "exprp.h"
static int rat_convert(Const, int *);
void gen_attribute(Node);
static int float_mantissa(int);
static void gen_type_attr(Symbol, int);
static int code_map(Symbol);
static int code_map_defined; /* set to FALSE if SETL version yields OM */
void gen_value(Node node) /*;gen_value*/
{
/*
* This procedure generates code for the v_expressions
* or, in other words, the right-hand-sides.
*
* - node is the tree expression for which code is to be generated.
*/
int save_tasks_declared, can_convert, rat_int;
Node pre_node, rec_type_node, id_node, static_node, init_node, obj_node,
exception_node, expr_node, init_call_node, task_node, entry_node,
index_node, value_node, arr_l_bd, arr_h_bd, val_l_bd, val_h_bd;
Symbol type_name, node_name, rec_type_name, proc_name, return_type,
obj_name, obj_type, model_name, exception_name, from_type, to_type,
accessed_type, discr_name;
Fortup ft1;
Symbol junk_var, comp_name, indx_type, value_type, indx_value_type;
Tuple stmts_list;
Node list_node, stmt_node, lhs, comp_node, type_node;
Tuple d_l, tup, indx_types;
Const value;
int i, stmts_list_i, size, ivalue;
long exprv; /* fixed point value */
#ifdef TRACE
if (debug_flag) {
gen_trace_node("GEN_VALUE", node);
}
#endif
while (N_KIND(node) == as_insert) {
FORTUP(pre_node = (Node), N_LIST(node), ft1);
compile(pre_node);
ENDFORTUP(ft1);
node = N_AST1(node);
}
type_name = get_type(node);
if (N_KIND(node) == as_null)
gen_s(I_PUSH_EFFECTIVE_ADDRESS, symbol_null);
else if (is_simple_name(node)) {
node_name = N_UNQ(node);
if (is_renaming(node_name)) {
gen_ks(I_PUSH, mu_addr, node_name);
if (is_array_type(type_name)) {
/* Note: can't be a renaming of a formal parm (transformed */
/* to normal variable). */
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
}
optional_deref(type_name);
}
else if (is_simple_type(type_name)) {
gen_ks(I_PUSH, kind_of(type_name), node_name);
}
else {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, node_name);
/* Arrays are treated in a different manner, depending on their */
/* nature: parameters, constants, variables... */
if (is_array_type(type_name)) {
if (is_formal_parameter(node_name)) {
/* For a parm, the type template follows the parameter */
/* in the stack */
gen_s(I_PUSH_EFFECTIVE_ADDRESS,
assoc_symbol_get(node_name, FORMAL_TEMPLATE));
}
else {
/* otherwise, the type template address is pushed on the */
/* stack */
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
}
}
}
}
else {
switch (N_KIND(node) ) {
case(as_create_task):
gen_s(I_CREATE_TASK, type_name);
break;
case(as_discard):
expr_node = N_AST1(node);
junk_var = new_unique_name("junk"); /* TBSL: Reusing same var */
next_local_reference(junk_var);
gen_ks(I_DECLARE, kind_of(N_TYPE(node)), junk_var);
gen_value(expr_node);
gen_ksc(I_POP, kind_of(N_TYPE(node)), junk_var,
"Used only for check");
break;
case(as_ivalue):
case(as_real_literal):
case(as_int_literal):
if (is_fixed_type(type_name)) {
exprv = rat_tof(get_ivalue(node),
small_of(base_type(type_name)), size_of(type_name));
/* the evaluation may have raised the overflow flag. Therefore,
* constraint_error has to be raised at execution time
*/
if ( ! arith_overflow) {
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name),
fixed_const(exprv));
}
else {
gen_s(I_LOAD_EXCEPTION_REGISTER, symbol_constraint_error);
gen(I_RAISE);
}
}
else if (is_simple_type(type_name)) {
value = get_ivalue(node);
if (is_float_type(type_name)) {
/* gen_(I_PUSH_IMMEDIATE, kind_of(type_name), value,
* ' = '+str(I_TO_F(value)));
*/
if (is_const_rat(value)) { /* try to cnvrt rtnl to real*/
chaos("expr.c: rational seen when real expected");
}
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name), value);
}
else {
if (is_const_rat(value)) { /* try to cnvrt rtnl to int */
rat_int = rat_convert(value, &can_convert);
if (can_convert) {
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name),
int_const(rat_int));
}
else {
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name), value);
}
}
else if (is_const_uint(value)) {
/* try to convert universal integer to integer */
ivalue = int_toi(UINTV(value));
if (!arith_overflow) {/* if can convert to integer */
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name),
int_const(ivalue));
}
else { /* just try again as universal integer */
gen_s(I_LOAD_EXCEPTION_REGISTER,
symbol_constraint_error);
gen(I_RAISE);
/* the exceptn has to be raised (overflow on int)
* gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name),
* value);
*/
}
}
else {
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name), value);
}
}
}
else
compiler_error("structured ivalue");
break;
case(as_string_ivalue):
/* This created a segment containing the string literal... */
/* TBSL: note that array_ivalue returns a Segment */
obj_name = get_constant_name(array_ivalue(node));
type_name = N_TYPE(node);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_name);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
break;
case(as_index):
gen_subscript(node);
optional_deref(type_name);
break;
case(as_selector):
gen_address(node);
optional_deref(type_name);
break;
case(as_discr_ref):
discr_name = N_UNQ(node);
rec_type_node = N_AST1(node);
rec_type_name = N_UNQ(rec_type_node);
gen_sc(I_PUSH_EFFECTIVE_ADDRESS, rec_type_name,
"fetch discriminant from template");
/* SETL version has discr_name as last argument, this is presumably
* comment part of instruction. For now ignore this
* gen_ki(I_ADD_IMMEDIATE, mu_word,
* TT_C_RECORD_DISCR + FIELD_OFFSET(discr_name)(TARGET),
* discr_name);
*/
/* TBSL: review trnsltn of next line VERY carefully ds 10-2-85 */
if (TYPE_KIND(rec_type_name) == TT_D_RECORD) {
gen_ki(I_ADD_IMMEDIATE, mu_word,
((sizeof(struct tt_d_type)/sizeof(int)) +
1 + 2 * FIELD_OFFSET(discr_name)));
}
else {
gen_ki(I_ADD_IMMEDIATE, mu_word,
((sizeof(struct tt_d_type)/sizeof(int))
+ FIELD_OFFSET(discr_name)));
}
gen_k(I_DEREF, kind_of(type_name));
break;
case(as_all):
gen_address(node);
if (is_simple_type(type_name)) {
gen_k(I_DEREF, kind_of(type_name));
}
else {
Symbol not_null;
/* test for null explicitly, because optional_deref is a noop
* on an array or record (which are always references).
*/
gen_k(I_DUPLICATE, mu_addr);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, symbol_null);
gen_k(I_COMPARE, mu_addr);
not_null = new_unique_name("ok_access");
gen_s(I_JUMP_IF_FALSE, not_null);
gen_s(I_LOAD_EXCEPTION_REGISTER, symbol_constraint_error);
gen(I_RAISE);
gen_s(I_LABEL, not_null);
}
break;
case(as_call):
id_node = N_AST1(node);
proc_name = N_UNQ(id_node);
return_type = TYPE_OF(proc_name);
gen_kc(I_DUPLICATE, kind_of(return_type), "place holder");
compile(node); /* processed from now as a procedure call */
break;
case(as_slice):
gen_address(node);
break;
case(as_raise):
compile(node);
break;
case(as_attribute):
case(as_range_attribute):
gen_attribute(node);
break;
case(as_record_aggregate):
case(as_record_ivalue):
static_node = N_AST1(N_AST1(node));
init_node = N_AST2(N_AST1(node));
obj_node = N_AST2(node);
obj_name = N_UNQ(obj_node);
obj_type = get_type(obj_node);
if (!has_static_size(obj_type)) {
next_local_reference(obj_name);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_type);
gen(I_CREATE_STRUC);
gen_s(I_UPDATE_AND_DISCARD, obj_name);
/* Warning: Discriminants may be static or not, but must be */
/* evaluated before other components */
if (static_node != OPT_NODE) {
stmts_list = tup_copy(N_LIST(static_node));
if (init_node != OPT_NODE) {
/* init_node is an as_statements */
list_node = N_AST1(init_node);
d_l = discriminant_list_get(obj_type);
FORTUP(stmt_node = (Node), N_LIST(list_node), ft1);
if (N_KIND(stmt_node) == as_assignment) {
/* lhs is as_selector */
lhs = N_AST1(stmt_node);
comp_node = N_AST2(lhs);
comp_name = N_UNQ(comp_node);
if (tup_mem((char *) comp_name, d_l)) {
/* This is a discriminant */
stmts_list = tup_exp(stmts_list,
tup_size(stmts_list)+1);
for (stmts_list_i = tup_size(stmts_list);
stmts_list_i > 1; stmts_list_i--) {
stmts_list[stmts_list_i] =
stmts_list[stmts_list_i-1];
}
stmts_list[1] = (char *)stmt_node;
}
else {
stmts_list =
tup_with(stmts_list, (char *) stmt_node);
}
}
else if (N_KIND(stmt_node) == as_init_call) {
tup = N_LIST(N_AST2(stmt_node));
size = tup_size(tup);
/* lhs is as_selector */
lhs = (Node) tup[size];
comp_node = N_AST2(lhs);
comp_name = N_UNQ(comp_node);
if (tup_mem((char *) comp_name, d_l)) {
/* This is a discriminant */
stmts_list = tup_exp(stmts_list,
tup_size(stmts_list)+1);
for (stmts_list_i = tup_size(stmts_list);
stmts_list_i > 1; stmts_list_i--) {
stmts_list[stmts_list_i] =
stmts_list[stmts_list_i-1];
}
stmts_list[1] = (char *)stmt_node;
}
else {
stmts_list =
tup_with(stmts_list, (char *) stmt_node);
}
}
else {
stmts_list = tup_with(stmts_list,
(char *) stmt_node);
}
ENDFORTUP(ft1);
}
FORTUP(comp_node = (Node), stmts_list, ft1)
compile(comp_node);
ENDFORTUP(ft1);
init_node = OPT_NODE; /* all done. */
}
}
else if (is_ivalue(node)) {
assign_same_reference(obj_name,
get_constant_name(record_ivalue(node)) );
}
else if (CURRENT_LEVEL == 1) {
next_global_reference_template(obj_name, record_ivalue(node));
}
else if (tup_size(N_LIST(static_node)) == 0) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_type);
gen(I_CREATE_STRUC);
next_local_reference(obj_name);
gen_s(I_UPDATE_AND_DISCARD, obj_name);
}
else {
model_name = get_constant_name(record_ivalue(node));
gen_s(I_PUSH_EFFECTIVE_ADDRESS, model_name);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_type);
gen(I_CREATE_COPY_STRUC);
next_local_reference(obj_name);
gen_s(I_UPDATE_AND_DISCARD, obj_name);
}
compile(init_node);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_name);
break;
case(as_array_aggregate):
case(as_array_ivalue):
static_node = N_AST1(N_AST1(node));
init_node = N_AST2(N_AST1(node));
obj_node = N_AST2(node);
obj_name = N_UNQ(obj_node);
obj_type = get_type(obj_node);
/* Check and see if can create a segment containing the aggregate
* value...
*/
if (!has_static_size(obj_type)) {
/* CASE 1. We cannot create a segment because have anon.
* types decl which are used for type checking at run time
*/
next_local_reference(obj_name);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_type);
gen(I_CREATE_STRUC);
if (is_array_type(obj_type)) {
gen_ks(I_DISCARD_ADDR, 1, obj_type);
}
gen_s(I_UPDATE_AND_DISCARD, obj_name);
FORTUP(comp_node = (Node), N_LIST(static_node), ft1);
compile(comp_node);
ENDFORTUP(ft1);
}
else if (is_ivalue(node)) {
/* TBSL: note that array_ivalue returns a Segment */
/* CASE 2. The aggregate is static and some (or all) values
* can be put into a segment for that aggregate.
*/
assign_same_reference(obj_name,
get_constant_name(array_ivalue(node)));
}
else if (CURRENT_LEVEL == 1) {
/* CASE 3. */
next_global_reference_template(obj_name, array_ivalue(node));
}
else if (tup_size(N_LIST(static_node)) == 0) {
/* CASE 4. There are no static values for the aggregate.
* Hence, all values are assigned with run-time assignment
* statements...
*/
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_type);
gen(I_CREATE_STRUC);
next_local_reference(obj_name);
gen_ks(I_DISCARD_ADDR, 1 , obj_type);
gen_s(I_UPDATE_AND_DISCARD, obj_name);
}
else {
/* CASE 5. There are both static values and non-static values
* for the aggregate. A segment is created with the static
* values, and non-static values are assigned with run-time
* assignment statements...
*/
model_name = get_constant_name(array_ivalue(node));
gen_s(I_PUSH_EFFECTIVE_ADDRESS, model_name);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_type);
gen(I_CREATE_COPY_STRUC);
next_local_reference(obj_name);
gen_ks(I_DISCARD_ADDR, 1, obj_type);
gen_s(I_UPDATE_AND_DISCARD, obj_name);
}
/* Proces the non-static value and push addresses of the obj_name
* and obj_type
*/
compile(init_node);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_name);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, obj_type);
break;
case(as_type_and_value):
/* Special node: generate a record value and elaborate a record */
/* subtype, constrained by the value's discriminants */
type_node = N_AST1(node);
expr_node = N_AST2(node);
type_name = N_UNQ(type_node);
gen_value(expr_node);
gen_subtype(type_name);
break;
case(as_test_exception):
exception_node = N_AST1(node);
exception_name = N_UNQ(exception_node);
gen_s(I_TEST_EXCEPTION_REGISTER, exception_name);
break;
case(as_convert):
expr_node = N_AST2(node);
from_type = base_type(get_type(expr_node));
to_type = N_TYPE(node);
gen_value(expr_node);
gen_convert(from_type, to_type);
break;
case(as_qual_discr):
type_name = N_TYPE(node);
value_node = N_AST1(node);
gen_value(value_node);
/* A qual_discr on a TT_D_RECORD is meaningless.
* Special code may be emitted TBSL.
*/
if (type_name != get_type(value_node)
&& TYPE_KIND(type_name) != TT_D_RECORD
&& SIGNATURE(type_name) != SIGNATURE(root_type(type_name))) {
gen_s(I_QUAL_DISCR, type_name);
}
break;
case(as_qual_range):
type_name = N_TYPE(node);
value_node = N_AST1(node);
gen_value(value_node);
gen_s(I_QUAL_RANGE, type_name);
break;
case(as_qual_index):
type_name = N_TYPE(node);
value_node = N_AST1(node);
gen_value(value_node);
value_type = get_type(value_node);
if (value_type != type_name && TYPE_KIND(type_name) != TT_D_ARRAY) {
gen_s(I_QUAL_INDEX, type_name);
}
/* the bounds of the value and the array itself must be equal. */
else if (value_type != type_name) { /* case of TT_D_ARRAY. */
indx_types = (Tuple)SIGNATURE(type_name)[1];
for (i = 1; i <= tup_size(indx_types); i++) {
indx_type = (Symbol)indx_types[i];
arr_l_bd = (Node)SIGNATURE(indx_type)[2];
arr_h_bd = (Node)SIGNATURE(indx_type)[3];
indx_value_type =
(Symbol)((Tuple)SIGNATURE(value_type)[1])[i];
val_l_bd = (Node)SIGNATURE(indx_value_type)[2];
val_h_bd = (Node)SIGNATURE(indx_value_type)[3];
if (is_ivalue(arr_l_bd) && is_ivalue(val_l_bd) &&
INTV(get_ivalue(arr_l_bd)) != INTV(get_ivalue(val_l_bd))){
gen_s(I_LOAD_EXCEPTION_REGISTER,
symbol_constraint_error);
gen(I_RAISE);
break;
}
if (is_ivalue(arr_h_bd) && is_ivalue(val_h_bd) &&
INTV(get_ivalue(arr_h_bd)) != INTV(get_ivalue(val_h_bd))){
gen_s(I_LOAD_EXCEPTION_REGISTER,
symbol_constraint_error);
gen(I_RAISE);
break;
}
}
}
break;
case(as_qual_sub):
type_name = N_TYPE(node);
value_node = N_AST1(node);
gen_value(value_node);
gen_s(I_QUAL_SUB, type_name);
break;
case(as_qual_adiscr):
type_name = (Symbol)designated_type(N_TYPE(node));
value_node = N_AST1(node);
gen_value(value_node);
gen_access_qual(as_qual_discr, type_name);
break;
case(as_qual_aindex):
type_name = (Symbol)designated_type(N_TYPE(node));
value_node = N_AST1(node);
gen_value(value_node);
gen_access_qual(as_qual_index, type_name);
break;
case(as_new):
type_node = N_AST1(node);
expr_node = N_AST2(node);
type_name = N_TYPE(node);
accessed_type = N_UNQ(type_node);
if (N_KIND(expr_node) == as_init_call) {
init_call_node = expr_node;
expr_node = OPT_NODE;
}
else {
init_call_node = OPT_NODE;
}
if (CONTAINS_TASK(accessed_type)) {
save_tasks_declared = TASKS_DECLARED;
TASKS_DECLARED = FALSE;
/* Note, make want to have global corresponding to this const */
gen_kv(I_PUSH_IMMEDIATE, mu_word, int_const_null_task);
gen_c(I_LINK_TASKS_DECLARED, "new task frame for allocator");
}
if (expr_node != OPT_NODE) {
gen_value(expr_node);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_s(I_ALLOCATE_COPY, accessed_type);
}
else {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, accessed_type);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen(I_ALLOCATE);
if (init_call_node != OPT_NODE) {
if (is_array_type(accessed_type)) {
gen_k(I_DUPLICATE, mu_addr);
gen_k(I_DEREF, mu_dble);
}
compile(init_call_node);
if (is_array_type(accessed_type)) {
gen_ks(I_DISCARD_ADDR, 2, (Symbol) 0);
}
}
}
if (CONTAINS_TASK(accessed_type)) {
gen_s(I_ACTIVATE_NEW, type_name);
TASKS_DECLARED = save_tasks_declared;
}
break;
case(as_entry_name):
task_node = N_AST1(node);
entry_node = N_AST2(node);
index_node = N_AST3(node);
if (task_node != OPT_NODE)
gen_value(task_node);
if (index_node == OPT_NODE) {
reference_of(N_UNQ(entry_node));
gen_kv(I_PUSH_IMMEDIATE, mu_byte,
int_const((int)REFERENCE_OFFSET));
gen_kvc(I_PUSH_IMMEDIATE, mu_word, int_const_0, "simple entry");
}
else {
reference_of(N_UNQ(entry_node));
gen_kvc(I_PUSH_IMMEDIATE, mu_byte,
int_const((int) REFERENCE_OFFSET), "family");
gen_value(index_node);
}
break;
case(as_current_task):
gen(I_CURRENT_TASK);
break;
/* Unary operators */
case(as_un_op):
gen_unary(node);
break;
/* Binary operators */
case(as_op):
gen_binary(node);
break;
case(as_deleted):
;
default:
compiler_error("Unknown node at GEN_VALUE");
}
}
}
static int rat_convert(Const con, int *can_convert) /*;rat_convert*/
{
int rat_int;
rat_int = rat_toi(RATV(con));
*can_convert = !arith_overflow;
return rat_int;
}
void gen_unary(Node node) /*;gen_unary*/
{
/* Unary operators */
Node op_node, args_node, op1;
Symbol opcode, type_name;
#ifdef TRACE
if (debug_flag)
gen_trace_node("GEN_UNARY", node);
#endif
op_node = N_AST1(node);
args_node = N_AST2(node);
opcode = N_UNQ(op_node);
type_name = N_TYPE(node);
op1 = (Node) N_LIST(args_node)[1];
gen_value(op1);
if (opcode == symbol_addui || opcode == symbol_addufl
|| opcode == symbol_addufx)
;
else if (opcode == symbol_subufx || opcode == symbol_subui)
gen_k(I_NEG, kind_of(type_name));
else if (opcode == symbol_subufl)
gen_k(I_FLOAT_NEG, kind_of(type_name));
else if (opcode == symbol_absi || opcode == symbol_absfx)
gen_k(I_ABS, kind_of(type_name));
else if (opcode == symbol_absfl)
gen_k(I_FLOAT_ABS, kind_of(type_name));
else if (opcode == symbol_not) {
if (is_array_type(type_name))
gen(I_ARRAY_NOT);
else
gen(I_NOT);
}
else
compiler_error("Unexpected unary operator");
}
void gen_binary(Node node) /*;gen_binary*/
{
/* The SETL constant code_map is realized in the C version by a procedure
* code_map().
*/
Node op_node, args_node, op1, op2;
Symbol opcode, type_name, andthen, orelse, op1_type, op2_type;
int op_instr, aopcode;
#ifdef TRACE
if (debug_flag)
gen_trace_node("GEN_BINARY", node);
#endif
op_node = N_AST1(node);
args_node = N_AST2(node);
opcode = N_UNQ(op_node);
type_name = N_TYPE(node);
op1 = (Node) N_LIST(args_node)[1];
op2 = (Node) N_LIST(args_node)[2];
if (opcode == symbol_and|| opcode == symbol_or || opcode == symbol_xor) {
gen_value(op1);
gen_value(op2);
if (is_array_type(type_name)) {
if (opcode == symbol_and) aopcode = I_ARRAY_AND;
else if (opcode == symbol_or) aopcode = I_ARRAY_OR;
else if (opcode == symbol_xor) aopcode = I_ARRAY_XOR;
gen(aopcode);
}
else {
gen(code_map(opcode));
}
}
else if (opcode == symbol_andthen) {
gen_value(op1);
gen_k(I_DUPLICATE, mu_byte);
andthen = new_unique_name("andthen");
gen_s(I_JUMP_IF_FALSE, andthen);
gen_value(op2);
gen(I_AND);
gen_s(I_LABEL, andthen);
}
else if(opcode == symbol_orelse) {
gen_value(op1);
gen_k(I_DUPLICATE, mu_byte);
orelse = new_unique_name("orelse");
gen_s(I_JUMP_IF_TRUE, orelse);
gen_value(op2);
gen(I_OR);
gen_s(I_LABEL, orelse);
}
else if (opcode == symbol_in || opcode == symbol_notin) {
op2_type = N_UNQ(op2);
if (is_record_type(op2_type) && !has_discriminant(op2_type)) {
gen_ki(I_PUSH_IMMEDIATE, mu_byte, opcode == symbol_in);
}
else {
if (is_access_type(op2_type)) {
/* if the acces value is null, it belongs to the subtype.
* Otherwise, it is the designated object that must belong
* to the designated subtype.
*/
Symbol desig_type, end_if, deref;
end_if = new_unique_name("end_if");
deref = new_unique_name("deref");
desig_type = designated_type(op2_type);
gen_value(op1);
gen_k(I_DUPLICATE, kind_of(op2_type));
gen_s(I_PUSH_EFFECTIVE_ADDRESS, symbol_null);
gen_k(I_COMPARE, mu_addr);
gen_s(I_JUMP_IF_FALSE, deref);
gen_ks(I_DISCARD_ADDR, 1, (Symbol)0);
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_boolean),
int_const(TRUE));
gen_s(I_JUMP, end_if);
gen_s(I_LABEL, deref);
if (is_simple_type(desig_type) || is_array_type(desig_type))
gen_k(I_DEREF, kind_of(desig_type));
gen_s(I_PUSH_EFFECTIVE_ADDRESS, desig_type); /* Type name */
gen(I_MEMBERSHIP);
gen_s(I_LABEL, end_if);
}
else {
gen_value(op1);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, op2_type); /* Type name */
gen(I_MEMBERSHIP);
}
if (opcode == symbol_notin)
gen(I_NOT);
}
}
else if (opcode == symbol_eq || opcode == symbol_ne || opcode == symbol_lt
|| opcode == symbol_gt || opcode == symbol_le ||opcode == symbol_ge){
gen_value(op1);
gen_value(op2);
op1_type = get_type(op1);
if (is_simple_type(op1_type)) {
if (is_float_type(op1_type))
gen_k(I_FLOAT_COMPARE, kind_of(op1_type));
else
gen_k(I_COMPARE, kind_of(op1_type));
}
else if (is_array_type(op1_type)) {
if (opcode == symbol_eq || opcode == symbol_ne)
gen(I_COMPARE_STRUC);
else
gen(I_COMPARE_ARRAYS);
}
else if (is_record_type(op1_type)) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, op1_type);
gen(I_COMPARE_STRUC);
}
/* Note: the compare operation push a byte on the stack whose two */
/* least significant bits mean 'is_equal' and 'is_greater' */
if(opcode == symbol_ne) {
gen(I_IS_EQUAL);
gen(I_NOT);
}
else {
gen(code_map(opcode));
}
}
else if (opcode == symbol_addi) {
if (is_ivalue(op1)) {
gen_value(op2);
gen_ki(I_ADD_IMMEDIATE, kind_of(type_name), get_ivalue_int(op1));
}
else if (is_ivalue(op2)) {
gen_value(op1);
gen_ki(I_ADD_IMMEDIATE, kind_of(type_name), get_ivalue_int(op2));
}
else {
gen_value(op1);
gen_value(op2);
gen_k(code_map(opcode), kind_of(type_name));
}
}
else if (opcode == symbol_subi) {
if (is_ivalue(op2)) {
gen_value(op1);
gen_ki(I_ADD_IMMEDIATE, kind_of(type_name), -get_ivalue_int(op2));
}
else {
gen_value(op1);
gen_value(op2);
gen_k(code_map(opcode), kind_of(type_name));
}
}
else if (opcode == symbol_cat) {
gen_value(op1);
gen_value(op2);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, base_type(type_name));
gen(I_ARRAY_CATENATE);
}
else if (opcode == symbol_mulfx || opcode == symbol_divfx) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_value(op1);
op1_type = get_type(op1);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, op1_type);
gen_value(op2);
op2_type = get_type(op2);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, op2_type);
gen(code_map(opcode));
/* note: a qual_range is done implicitly by the fix_xxx instruction */
}
else if (opcode == symbol_mulfxi || opcode == symbol_divfxi) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_value(op1);
op1_type = get_type(op1);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, op1_type);
gen_value(op2);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, symbol_integer);
gen_s(I_CONVERT_TO, symbol_dfixed);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, symbol_dfixed);
gen(code_map(opcode));
}
else if (opcode == symbol_mulfix) {
gen_value(op2);
op2_type = get_type(op2);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, op2_type);
gen_value(op1);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, symbol_dfixed);
gen(code_map(opcode));
}
else {
gen_value(op1);
gen_value(op2);
op_instr = code_map(opcode);
if (code_map_defined) {/*if code_map knows about opcode */
gen_k(op_instr, kind_of(type_name));
}
else
compiler_error("Unknown operator:");
}
}
void gen_attribute(Node node) /*;gen_attribute*/
{
/*SETL float_mantissa macro is procedure in C following this one.*/
/* const
* internal_map is not needed in C version.
* internal_map = {['T_FIRST', a_T_FIRST],
* ['T_LAST', a_T_LAST],
* ['T_LENGTH', a_T_LENGTH],
* ['T_RANGE', a_T_RANGE]};
*/
Const old_lbd, old_ubd;
Rational rat;
int *rat_n, *rat_d, *ivalue_i; /* multi-precision integers*/
Node lbd_node, ubd_node, delta_node, low, high;
int ivalue_n;
int fmantissa, digits_int, ivalue_int, i;
Tuple tup;
Const type_small, root_small;
int l, low_int, high_int;
Const low_value, high_value, digits, const_1, const_2, rat_const_v;
double fvalue;
Rational rvalue, rat_t;
Node arg1, arg2, comp_node, digs;
Symbol from_type, to_type, type_name, comp_name;
Symbol junk_var, field;
Tuple index_list;
int attribute;
long low_long, high_long, rvalue_long; /* fixed point */
Tuple repr_tup, align_info, attribute_list;
Fortup ft1;
#ifdef TRACE
if (debug_flag)
gen_trace_node("GEN_ATTRIBUTE", node);
#endif
arg1 = N_AST2(node);
arg2 = N_AST3(node);
attribute = (int) attribute_kind(node);
#ifdef TRACE
if (debug_flag)
gen_trace_string(" ATTRIBUTE:", attribute_str(attribute));
#endif
/*TBSL(JC): in GEN_ATTRIBUTE type of static attributes of real types */
switch (attribute) {
case(ATTR_ADDRESS):
gen_address(arg1);
break;
case(ATTR_AFT): /* Computed by the expander? TBSL */
type_name = N_UNQ(arg1);
tup = get_constraint(type_name);
delta_node = (Node) tup[4];
rat_const_v = get_ivalue(delta_node);
if (rat_const_v->const_kind != CONST_RAT)
chaos("expr: argument not rational");
rat = rat_const_v->const_value.const_rat;
ivalue_1 = int_fri(1);
ivalue_i = int_fri(1);
rat_n = num(rat);
rat_d = den(rat);
rat_n = int_mul(rat_n, int_fri(10));
while (int_lss(rat_n , rat_d)) {
ivalue_i = int_add(ivalue_i, ivalue_1);
rat_n = int_mul(rat_n, ivalue_10);
}
ivalue_n = int_toi(ivalue_i);
/* TBSL: may need extra check for long case here, though for now
* will crash if want long integer value as will get overflow
*/
if (arith_overflow)
chaos("expr.c ATTR_AFT overflow during conversion");
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer), int_const(ivalue_n));
break;
/* ("BASE): */
case(ATTR_CALLABLE):
gen_value(arg1);
gen_kv(I_ATTRIBUTE, ATTR_CALLABLE, int_const(0));
break;
/* ("T_CONSTRAINED"): */
case(ATTR_O_CONSTRAINED):
if (is_record_type(get_type(arg1))) {
gen_address(arg1); /* 1st field in record */
gen_kc(I_DEREF, mu_byte, "constrained flag");
}
else {
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_boolean), int_const(TRUE));
}
break;
case(ATTR_COUNT):
gen_value(arg1);
gen_kv(I_ATTRIBUTE, ATTR_COUNT, int_const(0));
break;
case (ATTR_DELTA):
to_type = N_TYPE(node);
type_name = N_UNQ(arg1);
tup = get_constraint(type_name);
delta_node = (Node)numeric_constraint_delta(tup);
rat_const_v = get_ivalue(delta_node);
/* convert rational value to indicated target type */
if (is_fixed_type(to_type)) {
rvalue_long = rat_tof(rat_const_v, small_of(base_type(to_type)),
size_of(to_type));
gen_kv(I_PUSH_IMMEDIATE,kind_of(to_type), fixed_const(rvalue_long));
}
else { /* can only be float */
fvalue = rat_tor(RATV(rat_const_v), ADA_REAL_DIGITS);
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_float), real_const(fvalue));
}
break;
case(ATTR_DIGITS): /* Folded by FE unless it appears in a generic */
type_name = N_UNQ(arg1);
tup = SIGNATURE(type_name);
digs = (Node) tup[4];
digits = get_ivalue(digs);
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer), digits);
break;
case(ATTR_EMAX): /* Folded by FE unless it appears in a generic */
type_name = N_UNQ(arg1);
tup = SIGNATURE(type_name);
digs = (Node) tup[4];
digits_int= get_ivalue_int(digs);
fmantissa = float_mantissa(digits_int);
gen_kv(I_PUSH_IMMEDIATE,kind_of(symbol_integer),int_const(4*fmantissa));
break;
case(ATTR_EPSILON): /* Folded by FE unless it appears in a generic */
type_name = N_UNQ(arg1);
tup = SIGNATURE(type_name);
digs = (Node) tup[4];
digits_int = get_ivalue_int(digs);
fmantissa = float_mantissa(digits_int);
fvalue = pow(2.0, -(double) (fmantissa-1));
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_float), real_const(fvalue));
break;
case(ATTR_T_FIRST):
case(ATTR_T_LAST):
case(ATTR_T_LENGTH):
case(ATTR_T_RANGE):
/* Note: cf. GEN_SUBTYPE for some optimizations on 'range */
type_name = N_UNQ(arg1);
if (is_array_type(type_name)) {
tup = SIGNATURE(type_name);
index_list = (Tuple) tup[1];
type_name = (Symbol) index_list[get_ivalue_int(arg2)];
}
tup = SIGNATURE(type_name);
low = (Node) tup[2];
high = (Node) tup[3];
low_value = get_ivalue(low);
high_value = get_ivalue(high);
if ((attribute == ATTR_T_RANGE) && (low_value->const_kind != CONST_OM
&& high_value->const_kind != CONST_OM)) {
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name), low_value);
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name), high_value);
return;
}
else if((attribute==ATTR_T_FIRST) && low_value->const_kind != CONST_OM){
if (is_fixed_type(type_name)) {
low_long= rat_tof(low_value, small_of(base_type(type_name)),
size_of(type_name));
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name),
fixed_const(low_long));
}
else {
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name), low_value);
}
return;
}
else if((attribute==ATTR_T_LAST) && high_value->const_kind != CONST_OM){
if (is_fixed_type(type_name)) {
high_long= rat_tof(high_value, small_of(base_type(type_name)),
size_of(type_name));
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name),
fixed_const(high_long));
}
else {
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name), high_value);
}
return;
}
else if((attribute==ATTR_T_LENGTH) && (l = length_of(type_name)) >= 0) {
gen_kv(I_PUSH_IMMEDIATE, kind_of(type_name), int_const(l));
return;
/* and in case none of the above worked */
}
else {
gen_type_attr(type_name, attribute);
}
break;
case(ATTR_O_FIRST):
gen_value(arg1);
gen_kv(I_ATTRIBUTE, ATTR_O_FIRST, get_ivalue(arg2));
break;
case(ATTR_FIRST_BIT):
case(ATTR_LAST_BIT):
case(ATTR_POSITION):
comp_node = N_AST2(arg1);
type_name = TYPE_OF(N_UNQ(N_AST1(arg1)));
comp_name = N_UNQ(comp_node);
repr_tup= REPR(type_name);
align_info = (Tuple) repr_tup[4]; /* alignment_info*/
attribute_list = (Tuple) align_info[2];
FORTUP(tup=(Tuple),attribute_list,ft1);
field = (Symbol) tup[1];
if (comp_name == field) {
if (attribute == ATTR_POSITION) {
ivalue_int = (int) tup[2]; /* position */
}
else if (attribute == ATTR_FIRST_BIT) {
ivalue_int = (int) tup[3]; /* first_bit */
}
else {
ivalue_int = (int) tup[4]; /* last_bit */
}
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer),
int_const(ivalue_int));
return;
}
ENDFORTUP(ft1);
break;
case(ATTR_FORE):
type_name = N_UNQ(arg1);
if (is_static_type(type_name)) {
tup = get_constraint(type_name);
lbd_node = (Node) tup[2];
ubd_node = (Node) tup[3];
old_lbd = get_ivalue(lbd_node);
old_ubd = get_ivalue(ubd_node);
if (rat_gtr(rat_abs(RATV(old_lbd)), rat_abs(RATV(old_ubd))) ) {
rat_t = rat_abs(RATV(old_lbd));
rat_n = num(rat_t);
rat_d = den(rat_t);
/*[n, d] = rat_abs(old_lbd);*/
}
else {
/*[n, d] = rat_abs(old_ubd);*/
rat_t = rat_abs(RATV(old_ubd));
rat_n = num(rat_t);
rat_d = den(rat_t);
}
ivalue_n = 2;
while (int_geq(int_quo(rat_n , rat_d) , ivalue_10)) {
rat_d = int_mul(rat_d, ivalue_10);
ivalue_n += 1;
}
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer),
int_const(ivalue_n));
}
else {
rat_const_v = small_of(base_type(type_name));
rat = RATV(rat_const_v);
rat_n = num(rat);
rat_d = den(rat);
gen_kv(I_PUSH_IMMEDIATE, mu_word, int_const(int_toi(rat_n)));
gen_kv(I_PUSH_IMMEDIATE, mu_word, int_const(int_toi(rat_d)));
gen_type_attr(type_name, ATTR_FORE);
}
break;
case(ATTR_IMAGE):
type_name = N_UNQ(arg1);
gen_value(arg2);
gen_type_attr(type_name, ATTR_IMAGE);
break;
case(ATTR_LARGE):
type_name = N_UNQ(arg1);
to_type = N_TYPE(node);
if (is_fixed_type(type_name)) {
Rational rt, rb;
int* small_ratio;
int* scaled_large;
rt = RATV(small_of(type_name));
rb = RATV(small_of(base_type(type_name)));
rvalue = rat_div(rt, rb);
small_ratio = int_quo(num(rvalue), den(rvalue));
if (is_static_type(type_name)) {
tup = get_constraint(type_name);
lbd_node = (Node) tup[2];
ubd_node = (Node) tup[3];
old_lbd = get_ivalue(lbd_node);
old_ubd = get_ivalue(ubd_node);
/* large = (2 ** mantissa -1) * small
* The run-time representation is in units of the base small,
* but of course the mantissa is that of the type, not the base.
* We scale the result by the ratios of the two smalls.
*/
scaled_large = int_mul(int_sub(int_exp(int_fri(2),
int_fri(fx_mantissa(RATV(old_lbd), RATV(old_ubd), rt))),
int_fri(1)), small_ratio);
if (is_fixed_type(to_type)) {
/* emit as fixed point number, i.e. long value */
gen_kv(I_PUSH_IMMEDIATE, kind_of(to_type),
fixed_const(int_tol(scaled_large)));
}
else { /* convert to floating type */
Rational rat_val;
rat_val = rat_new(int_mul(scaled_large, num(rb)), den(rb));
fvalue = rat_tor(rat_val, ADA_REAL_DIGITS);
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_float),
real_const(fvalue));
}
}
else {
/* Compute ratio between subtype's SMALL and base type's */
/* SMALL and push it (always integer) */
gen_kv(I_PUSH_IMMEDIATE, mu_word,
int_const(int_toi(small_ratio)));
gen_type_attr(type_name, ATTR_LARGE);
if(base_type(type_name) != base_type(to_type))
gen_convert(type_name, to_type);
}
}
else { /*floating points: folded by FE unless it appears in a generic */
tup = SIGNATURE(type_name);
digs = (Node) tup[4];
digits_int = get_ivalue_int(digs);
fmantissa = float_mantissa(digits_int);
fvalue = (1.0-(pow(2.0, -(double) fmantissa)))
* pow(2.0, (4.0 * fmantissa));
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_float), real_const(fvalue));
}
break;
/* ("T_LAST"): $ cf 'T_FIRST' */
case(ATTR_O_LAST):
gen_value(arg1);
gen_kv(I_ATTRIBUTE, ATTR_O_LAST, get_ivalue(arg2));
break;
/* ("T_LENGTH"): $ cf 'T_FIRST' */
case(ATTR_O_LENGTH):
gen_value(arg1);
gen_kv(I_ATTRIBUTE, ATTR_O_LENGTH, get_ivalue(arg2));
break;
case(ATTR_MACHINE_EMAX):
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer), int_const(127));
break;
case(ATTR_MACHINE_EMIN):
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer), int_const(-128));
break;
case(ATTR_MACHINE_MANTISSA):
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer), int_const(24));
break;
case(ATTR_MACHINE_OVERFLOWS):
gen_kv(I_PUSH_IMMEDIATE, mu_byte, int_const(TRUE));
break;
case(ATTR_MACHINE_RADIX):
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer), int_const(2));
break;
case(ATTR_MACHINE_ROUNDS):
gen_kv(I_PUSH_IMMEDIATE, mu_byte, int_const(TRUE));
break;
case(ATTR_MANTISSA):
type_name = N_UNQ(arg1);
if (is_fixed_type(type_name)) {
if (is_static_type(type_name) ) {
tup = get_constraint(type_name);
lbd_node = (Node) tup[2];
ubd_node = (Node) tup[3];
old_lbd = get_ivalue(lbd_node);
old_ubd = get_ivalue(ubd_node);
ivalue_int = fx_mantissa(RATV(old_lbd), RATV(old_ubd),
RATV(small_of(type_name)));
gen_kv(I_PUSH_IMMEDIATE, mu_word, int_const(ivalue_int));
}
else {
/* Compute ratio between subtype's SMALL and base type's */
/* SMALL and push it (always integer) */
const_1 = small_of(type_name);
const_2 = small_of(base_type(type_name));
rvalue = rat_div(RATV(const_1), RATV(const_2));
gen_kv(I_PUSH_IMMEDIATE, mu_word,
int_const(int_toi(int_quo(num(rvalue) , den(rvalue)))));
gen_type_attr(type_name, ATTR_MANTISSA);
}
}
else { /*floating points: folded by FE unless it appears in a generic */
tup = SIGNATURE(type_name);
digs = (Node) tup[4];
digits_int = get_ivalue_int(digs);
ivalue_int = float_mantissa(digits_int);
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer),
int_const(ivalue_int));
}
break;
/* ("POS"): $ Transformed by expander */
case(ATTR_PRED):
type_name = N_UNQ(arg1);
gen_value(arg2);
gen_type_attr(type_name, ATTR_PRED);
break;
/* ("T_RANGE"): $ cf 'T_FIRST' */
case(ATTR_O_RANGE):
gen_value(arg1);
gen_kv(I_ATTRIBUTE, ATTR_O_RANGE, get_ivalue(arg2));
break;
case(ATTR_SAFE_EMAX):
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer), int_const(127));
break;
case(ATTR_SAFE_LARGE):
/* chaos("expr.c - untranslated code reached"); */
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_float),
real_const(ADA_MAX_REAL));
break;
case(ATTR_SAFE_SMALL):
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_float),
real_const(pow(2.0, -129.0)));
break;
case(ATTR_T_SIZE):
type_name = N_UNQ(arg1);
if (has_static_size(type_name)) {
repr_tup = REPR(type_name);
if (repr_tup != (Tuple)0) {
ivalue_int = (int) repr_tup[2]; /* size */
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer),
int_const(ivalue_int));
}
else { /* size representation not counted due to some error */
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_integer),
int_const(BITS_SU * size_of(type_name)));
}
}
else {
gen_type_attr(type_name, ATTR_SIZE);
}
break;
case(ATTR_O_SIZE):
/* The evaluation of this attribute has to evaluate the object
* because this evaluation may raise an exception, for example.
* Therefore we have a junk variable that is just used for this
* purpose. Since there is no O_SIZE attribute in the Ada machine, the
* size of the object is still calculated from T_SIZE
*/
type_name = get_type(N_AST2(node));
if (is_simple_name (N_AST2 (node)) && !is_unconstrained (type_name)) {
/* this is the simplest case */
gen_type_attr(type_name, ATTR_SIZE);
}
else if ((!is_unconstrained(type_name)) && (!is_array_type(type_name))){
/* the object has to be evaluated */
junk_var = new_unique_name("junk"); /*TBSL:Reusing same variable */
next_local_reference(junk_var);
gen_ks(I_DECLARE, kind_of(type_name), junk_var);
gen_value(N_AST2(node));
gen_ksc(I_POP, kind_of(type_name), junk_var,
"Used only for eval. attr. size");
gen_type_attr(type_name, ATTR_SIZE);
}
else {
gen_value(N_AST2(node));
gen_kv(I_ATTRIBUTE, ATTR_SIZE, int_const(0));
if (is_array_type (type_name)) {
/* TBSL: Reusing same variable */
junk_var = new_unique_name("junk");
next_local_reference(junk_var);
gen_ks(I_DECLARE, kind_of(symbol_integer), junk_var);
gen_ksc(I_POP, kind_of(symbol_integer), junk_var,
"Used only for eval. attr. size");
gen_ks (I_DISCARD_ADDR, 1, (Symbol) 0);
gen_ks(I_PUSH, kind_of(symbol_integer), junk_var);
}
}
break;
case(ATTR_SMALL):
type_name = N_UNQ(arg1);
to_type = N_TYPE(node);
if (is_fixed_type(type_name)) {
type_small = small_of(type_name);
root_small = small_of(base_type(type_name));
if (is_fixed_type(to_type)) {
rvalue_long = rat_tof(type_small, small_of(base_type(to_type)),
size_of(to_type));
gen_kv(I_PUSH_IMMEDIATE, kind_of(to_type),
fixed_const(rvalue_long));
}
else { /* convert to floating type */
fvalue = rat_tor(RATV(type_small), ADA_REAL_DIGITS);
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_float),
real_const(fvalue));
}
}
else { /*floating points: folded by FE unless it appears in a generic */
tup = SIGNATURE(type_name);
digs = (Node) tup[4];
digits_int = get_ivalue_int(digs);
fmantissa = float_mantissa(digits_int);
fvalue = pow(2.0, (-4.0*fmantissa-1.0));
gen_kv(I_PUSH_IMMEDIATE, kind_of(symbol_float), real_const(fvalue));
}
break;
case(ATTR_STORAGE_SIZE):
if (N_KIND(arg1) == as_all) { /* form of Obj.all'STORAGE_SIZE */
type_name = get_type(N_AST1(arg1));
}
else {
type_name = N_UNQ(arg1);
}
/*
* Since the collection size information is kept in the access
* template only , we must generate a reference to the base type
* in the case of STORAGE_SIZE on a subtype.
*/
if (NATURE(type_name) == na_subtype) {
type_name = base_type(type_name);
}
gen_type_attr(type_name, ATTR_STORAGE_SIZE);
break;
case(ATTR_SUCC):
type_name = N_UNQ(arg1);
gen_value(arg2);
gen_type_attr(type_name, ATTR_SUCC);
break;
case(ATTR_TERMINATED):
gen_value(arg1);
gen_kv(I_ATTRIBUTE, ATTR_TERMINATED, int_const(0));
break;
case(ATTR_VAL):
from_type = base_type(get_type(arg2));
to_type = N_TYPE(node);
gen_value(arg2);
gen_convert(from_type, to_type);
gen_s(I_QUAL_RANGE, to_type);
break;
case(ATTR_VALUE):
type_name = N_UNQ(arg1);
gen_value(arg2);
gen_type_attr(type_name, ATTR_VALUE);
break;
case(ATTR_WIDTH):
type_name = N_UNQ(arg1);
if (is_static_type(type_name)) {
tup = SIGNATURE(type_name);
low = (Node) tup[2];
high = (Node) tup[3];
low_value = get_ivalue (low);
high_value = get_ivalue (high);
/* this following test has been added because the bounds of the
* range may be not static. In the previous version there was an
* error during the get_ivalue_int
*/
if (low_value->const_kind == CONST_OM
|| high_value->const_kind == CONST_OM) {
gen_type_attr(type_name, ATTR_WIDTH);
}
else {
low_int = get_ivalue_int(low);
high_int = get_ivalue_int(high);
if (is_integer_type(type_name)) {
if (low_int > high_int)
gen_kv(I_PUSH_IMMEDIATE, mu_word, int_const(0));
else {
char *val_str = emalloct(10, "gen-attr-wid-1");
low_int = abs (low_int);
high_int = abs (high_int);
ivalue_int = (low_int > high_int ? low_int : high_int);
sprintf(val_str, " %d", ivalue_int);
ivalue_int = strlen(val_str);
efreet(val_str, "gen-attr-wid-2");
gen_kv(I_PUSH_IMMEDIATE, mu_word,int_const(ivalue_int));
}
}
/* following code does not work for bool and char.
* disable for now.
*/
else { /* Enumeration types */
int len, v;
tup = (Tuple) literal_map(root_type(type_name));
ivalue_int = 0;
for (i = 1; i <= tup_size(tup); i += 2) {
len = strlen(tup[i]);
v = (int) tup[i+1];
if (len > ivalue_int && (v >= low_int && v <= high_int))
ivalue_int = len;
}
gen_kv(I_PUSH_IMMEDIATE, mu_word, int_const(ivalue_int));
}
}
}
else { /* Not static types */
gen_type_attr(type_name, ATTR_WIDTH);
}
break;
default:
compiler_error("Unexpected attribute ");
}
}
static int float_mantissa(int digits) /*;float_mantissa*/
{
return (digits < 4 ? (3 * digits + 2) : (3 * digits + 3) );
}
static void gen_type_attr(Symbol type_name, int a_attribute) /*;gen_type_attr*/
{
gen_s(I_PUSH_EFFECTIVE_ADDRESS, type_name);
gen_kv(I_ATTRIBUTE, a_attribute, int_const(0));
}
void gen_convert(Symbol from_type, Symbol to_type) /*;gen_convert*/
{
if (is_fixed_type(from_type) && is_integer_type(to_type)) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, from_type);
gen_s(I_CONVERT_TO, symbol_dfixed);
from_type = symbol_dfixed;
}
else if (is_integer_type(from_type) && is_fixed_type(to_type)) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, from_type);
gen_s(I_CONVERT_TO, symbol_dfixed);
from_type = symbol_dfixed;
}
if (!is_array_type(from_type)) {
gen_s(I_PUSH_EFFECTIVE_ADDRESS, from_type);
}
if (is_array_type(to_type) && is_unconstrained(to_type)) {
gen_s(I_QUAL_SUB, to_type);
}
else {
gen_s(I_CONVERT_TO, to_type);
}
}
void gen_access_qual(int qualifier, Symbol type_name) /*;gen_access_qual*/
{
Symbol null_access;
gen_k(I_DUPLICATE, mu_addr);
gen_s(I_PUSH_EFFECTIVE_ADDRESS, symbol_null);
gen_k(I_COMPARE, mu_addr);
null_access = new_unique_name("null_access");
gen_s(I_JUMP_IF_TRUE, null_access);
if (qualifier == as_qual_index) {
gen_k(I_DUPLICATE, mu_addr);
gen_k(I_DEREF, mu_dble);
gen_s(I_QUAL_INDEX, type_name);
gen_ks(I_DISCARD_ADDR, 2, (Symbol)0);
}
else if (qualifier == as_qual_discr) {
/* Note: an access to a record type does not require
* any derefencing!
*/
gen_s(I_QUAL_DISCR, type_name);
}
else
compiler_error("Illegal access qual");
gen_s(I_LABEL, null_access);
}
Segment array_ivalue(Node node) /*;array_ivalue*/
{
/* Returns the ivalue part of an array object, i.e. a segment having the
* size of the object, with all static components initialized
* In C, the returned value is a Segment.
*/
Node static_node, selector_node, val_node, static_comp_node,
access_node, list_node;
Symbol obj_type, comp_type, selector_name;
Tuple tup, subscript_list; /* tuple(integer); */
int offset, i, index, comp_size, str_len, nk, n;
Segment res, obj_value;
Tuple tupstr, index_list;
Const exprv;
Fortup ft1;
#ifdef TRACE
if (debug_flag)
gen_trace_node("ARRAY_IVALUE", node);
#endif
nk = N_KIND(node);
if (nk == as_string_ivalue) {
/* CASE 1. String
* Create a segment and copy the characters from the string tuple
* to the data segment
*/
tupstr = (Tuple) N_VAL(node);
n = tup_size(tupstr);
res = segment_new(SEGMENT_KIND_DATA, n);
for (i = 1; i <= n; i++)
segment_put_word(res, (int) tupstr[i]);
return res;
}
else if (nk == as_array_aggregate || nk == as_array_ivalue) {
/* CASE 2: arr_aggreagate -or- array_ivalue
* Note: obj_type may be unconstrained in the case where the array
* subtype is identical to the base type. (not "really" unconstrained).
*/
static_node = N_AST1(N_AST1(node));
obj_type = N_TYPE(node);
if (!has_static_size(obj_type)) {
compiler_error("Ivalue of not static size array aggr.");
return segment_new(SEGMENT_KIND_DATA, 0);
}
/* Step 1: Create a segment and initialize it */
obj_value = segment_new(SEGMENT_KIND_DATA, size_of(obj_type));
for (i = 0; i < size_of(obj_type); i++)
segment_put_word(obj_value, 0);
/* Step 2: Calculate the offset for each static component */
FORTUP(static_comp_node = (Node), N_LIST(static_node), ft1);
offset = 0;
access_node = N_AST1(static_comp_node);
val_node = N_AST2(static_comp_node);
while (!is_simple_name(access_node)) {
if (N_KIND(access_node) == as_index){
list_node = N_AST2(access_node);
access_node = N_AST1(access_node);
obj_type = get_type(access_node);
tup = SIGNATURE(obj_type);
index_list = (Tuple) tup[1];
comp_type = (Symbol) tup[2];
comp_size = size_of(comp_type);
subscript_list = N_LIST(list_node);
index = compute_index(subscript_list, index_list);
offset += index*comp_size;
}
else if (N_KIND(access_node) == as_selector) {
selector_node = N_AST2(access_node);
access_node = N_AST1(access_node);
obj_type = get_type(access_node);
selector_name = N_UNQ (selector_node);
comp_type = TYPE_OF(selector_name);
offset += FIELD_OFFSET(selector_name);
}
else {
compiler_error("Incoherent access list in array agg.");
break;
}
}
/* Step 3: Copy the component value into the correct position
* in the segment
*/
if (N_KIND(val_node) == as_string_ivalue) {
segment_set_pos(obj_value, (unsigned) offset, 0);
tup = (Tuple) N_VAL(val_node);
str_len = tup_size(tup);
for (i = 1; i <= str_len; i++)
segment_put_word(obj_value, (int) tup[i]);
}
else if (N_KIND(val_node) == as_ivalue
|| N_KIND(val_node) == as_int_literal
|| N_KIND(val_node) == as_real_literal) {
exprv = get_ivalue(val_node);
comp_type = N_TYPE(val_node);
if (is_fixed_type(comp_type)) {
/* we have to take into account if the node val is fixed */
exprv = fixed_const(rat_tof( exprv,
small_of(base_type(comp_type)), size_of(comp_type)));
}
if (is_const_uint(exprv)) {
/* try to convert universal integer to integer */
i= int_toi(UINTV(exprv));
if (arith_overflow) {/* if cannot convert to integer */
chaos("cannot convert uint to int in array_ivalue");
}
exprv = int_const(i);
}
segment_set_pos(obj_value, offset, 0);
segment_put_const(obj_value, exprv);
/* segment_set_pos(obj_value, (unsigned) offset, 0);
* segment_put_const(obj_value, get_ivalue(val_node));
*/
}
else {
compiler_error("Static comp in array aggregate not ivalue");
}
ENDFORTUP(ft1);
}
/* there was an error message here */
return obj_value;
}
Segment record_ivalue(Node node) /*;record_ivalue*/
{
/* Returns the ivalue part of a record object, i.e. a tuple having the
* size of the object, with all static components initialized
* In C, the returned value is a segment.
*/
Node static_node, selector_node, val_node;
Node static_comp_node, access_node, list_node;
Symbol obj_type, comp_type, selector_name;
Segment obj_value; /* tuple(integer); */
int i, index, comp_size, nk;
Fortup ft1;
Segment sval;
Const exprv;
Tuple tup, subscript_list, index_list;
unsigned offset;
Segment tempseg;
sval = segment_new(SEGMENT_KIND_DATA, 1);
nk = N_KIND(node);
if (nk == as_record_aggregate || nk == as_record_ivalue) {
static_node = N_AST1(N_AST1(node));
/*init_node = N_AST2(node); -- init_node not used ds 7-8-85 */
/*name_node = N_AST3(node); -- name_node not used ds 7-8-85*/
obj_type = N_TYPE(node);
if (! has_static_size(obj_type)) {
compiler_error("Ivalue of not static size record aggr.");
return sval;
}
/* TBSL: see that obj_value properly intialized ds 6-26-85*/
obj_value = segment_new(SEGMENT_KIND_DATA, size_of(obj_type));
/* obj_value = [1..size_of(obj_type)];*/
FORTUP(static_comp_node = (Node), N_LIST(static_node), ft1);
offset = 0; /* a segment start at position 0 in c version */
access_node = N_AST1(static_comp_node);
val_node = N_AST2(static_comp_node);
while (! is_simple_name(access_node)) {
nk = N_KIND(access_node);
if (nk == as_index) {
list_node= N_AST2(access_node);
access_node = N_AST1(access_node);
obj_type = get_type(access_node);
tup = SIGNATURE(obj_type);
index_list = (Tuple) tup[1];
comp_type = (Symbol) tup[2];
comp_size = size_of(comp_type);
subscript_list = N_LIST(list_node);
index = compute_index(subscript_list, index_list);
offset += index*comp_size;
}
else if (nk == as_selector) {
selector_node = N_AST2(access_node);
access_node = N_AST1(access_node);
obj_type = get_type(access_node);
selector_name = N_UNQ(selector_node);
comp_type = TYPE_OF(selector_name);
offset += FIELD_OFFSET(selector_name);
}
else {
compiler_error("Incoherent access list in record agg.");
break;
}
}
/* We have now reached a simple type ivalue */
nk = N_KIND(val_node);
if (nk == as_string_ivalue) {
tup = (Tuple) N_VAL(val_node);
segment_set_pos(obj_value, offset, 0);
for (i = 1; i<= tup_size(tup); i++)
segment_put_int(obj_value, (int) tup[i]);
}
else if (nk == as_array_ivalue) {
tempseg = array_ivalue(val_node);
segment_set_pos(obj_value, offset, 0);
for (i = 0; i < segment_get_maxpos(tempseg); i ++) {
segment_put_int(obj_value,
(int) segment_get_int(tempseg, i));
}
}
else if (nk == as_ivalue || nk == as_int_literal
|| nk == as_real_literal) {
exprv = get_ivalue(val_node);
comp_type = N_TYPE(val_node);
if (is_fixed_type(comp_type)) {
exprv = fixed_const(rat_tof( exprv,
small_of(base_type(comp_type)), size_of(comp_type)));
}
segment_set_pos(obj_value, offset, 0);
segment_put_const(obj_value, exprv);
}
else
compiler_error("Static component in aggregate not ivalue");
ENDFORTUP(ft1);
}
else {
compiler_error_k("Not implemented : ", val_node);
compiler_error("record_ivalue - unknown node kind");
}
/*
* Initialize the rest of the segment with zeros. Note that this value
* has to be the same in intb.c - create_struc.
* This affects only unconstrained records.
*/
segment_set_pos(obj_value, (unsigned) segment_get_maxpos(obj_value), 0);
for (i = segment_get_pos(obj_value); i < size_of(obj_type); i++) {
segment_put_int(obj_value, 0);
}
return obj_value;
}
static int code_map(Symbol opcode) /*;code_map*/
{
code_map_defined = TRUE; /* assume can map to machine instruction */
if (opcode == symbol_and) return I_AND;
else if (opcode == symbol_or) return I_OR;
else if (opcode == symbol_xor) return I_XOR;
else if (opcode == symbol_eq) return I_IS_EQUAL;
else if (opcode == symbol_ne) return I_NOT;
else if (opcode == symbol_le) return I_IS_LESS_OR_EQUAL;
else if (opcode == symbol_gt) return I_IS_GREATER;
else if (opcode == symbol_ge) return I_IS_GREATER_OR_EQUAL;
else if (opcode == symbol_lt) return I_IS_LESS;
else if (opcode == symbol_addi) return I_ADD;
else if (opcode == symbol_subi) return I_SUB;
else if (opcode == symbol_addfx) return I_ADD;
else if (opcode == symbol_subfx) return I_SUB;
else if (opcode == symbol_muli) return I_MUL;
else if (opcode == symbol_divi) return I_DIV;
else if (opcode == symbol_remi) return I_REM;
else if (opcode == symbol_modi) return I_MOD;
else if (opcode == symbol_expi) return I_POW;
else if (opcode == symbol_addfl) return I_FLOAT_ADD;
else if (opcode == symbol_subfl) return I_FLOAT_SUB;
else if (opcode == symbol_mulfl) return I_FLOAT_MUL;
else if (opcode == symbol_divfl) return I_FLOAT_DIV;
else if (opcode == symbol_expfl) return I_FLOAT_POW;
else if (opcode == symbol_mulfix) return I_FIX_MUL;
else if (opcode == symbol_mulfxi) return I_FIX_MUL;
else if (opcode == symbol_mulfx) return I_FIX_MUL;
else if (opcode == symbol_divfxi) return I_FIX_DIV;
else if (opcode == symbol_divfx) return I_FIX_DIV;
else {
code_map_defined = FALSE;
return 0;
}
}